//
// Created on 2023/11/23.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".
#include "threadsafe_manager.h"
#include <iostream>
#include <hilog/log.h>
#define LOG_DOMAIN 0x0202
#define LOG_TAG "ThreadSafe_TAG"

#include "napi/native_api.h"
#include <thread>
#include <hitrace/trace.h>

#define CHECK_STATUS(status, name)                                                                                     \
    if (status) {                                                                                                      \
        OH_LOG_ERROR(LOG_APP, "ThreadSafeManager %{public}s failed!", name);                                           \
        return false;                                                                                                  \
    }
    namespace threadsafe {
TSInfo::TSInfo(string name, napi_threadsafe_function_call_js callJS, napi_finalize cb, void *data) {
    this->name = name;
    this->jsCallBack = callJS;
    this->jsFinalizeCallBack = cb;
    this->finalizeData = data;
    return;
}

ThreadSafeManager &ThreadSafeManager::GetThreadSafeManager() {
    static ThreadSafeManager threadSafeManager;
    return threadSafeManager;
}

/*
 * NAPI_EXTERN napi_status
   napi_call_threadsafe_function(napi_threadsafe_function func,
                                 void* data,
                                 napi_threadsafe_function_call_mode is_blocking);
 * */
bool ThreadSafeManager::Call(string funcName, void *data, napi_threadsafe_function_call_mode isBlocking) {
    unique_lock<mutex> lock(functionsLock_);
    auto iter = functions_.find(funcName);
    if (iter == functions_.end()) {
        OH_LOG_ERROR(LOG_APP, "Cannot find threadsafe function: %{public}s", funcName.c_str());
        return false;
    }
    auto fn = iter->second;
    napi_status status;
    status = napi_acquire_threadsafe_function(fn);
    CHECK_STATUS(status, "Call");
    
    status = napi_call_threadsafe_function(fn, data, isBlocking);
    return status == napi_ok;
}

/*
 * NAPI_EXTERN napi_status
   napi_create_threadsafe_function(napi_env env,
                                   napi_value func,
                                   napi_value async_resource,
                                   napi_value async_resource_name,
                                   size_t max_queue_size,
                                   size_t initial_thread_count,
                                   void* thread_finalize_data,
                                   napi_finalize thread_finalize_cb,
                                   void* context,
                                   napi_threadsafe_function_call_js call_js_cb,
                                   napi_threadsafe_function* result);
 * */
bool ThreadSafeManager::CreateThreadSafeFunction(napi_env env, napi_value cb, TSInfo *tsInfo) {
    unique_lock<mutex> lock(functionsLock_);
    napi_value name;
    napi_status status;
    status = napi_create_string_utf8(env, "Thread-safe Function", NAPI_AUTO_LENGTH, &name);
    CHECK_STATUS(status, "CreateThreadSafeFunction");
    napi_threadsafe_function tsfunc;
    status = napi_create_threadsafe_function(env, cb, nullptr, name, tsInfo->maxQueueSize, 1, tsInfo->finalizeData,
                                             tsInfo->jsFinalizeCallBack, tsInfo, tsInfo->jsCallBack, &tsfunc);
    CHECK_STATUS(status, "CreateThreadSafeFunction");
    SetThreadSafeFuntion(tsInfo->name, tsfunc);
    return true;
}

void ThreadSafeManager::RemoveThreadSafeFunction(string name, napi_threadsafe_function_release_mode mode) {
    unique_lock<mutex> lock(functionsLock_);
    auto iter = functions_.find(name);
    if (iter == functions_.end()) {
        return;
    }
    functions_.erase(iter);
    napi_status status = napi_release_threadsafe_function(iter->second, mode);
    if (status) {
        OH_LOG_INFO(LOG_APP, "ThreadSafe function is closed");
    }
    OH_LOG_INFO(LOG_APP, "ThreadSafe function is RemoveThreadSafeFunction");
}

void ThreadSafeManager::Print() { OH_LOG_INFO(LOG_APP, "print ThreadSafeManager"); }
} // namespace threadsafe